package com.keguoyu.easymvp.commons.supplier;

import java.util.Map;

import com.keguoyu.easymvp.commons.RootParam;

public enum SupplierGenerator {

  ME;

  public static SupplierGenerator me() {
    return ME;
  }

  private static final SupplierInterface<Object> DEFAULT = new SupplierInterface<Object>() {
    @Override
    public void addToWrapper(SupplierContainer wrapper, Object target) {
      wrapper.put(target.getClass(), new SelfSupplier(target));
    }
  };

  private static final SupplierInterface<RootParam> NAMED_PARAM = new SupplierInterface<RootParam>() {
    @Override
    public void addToWrapper(SupplierContainer wrapper, RootParam accessible) {
      wrapper.put(accessible.getKey(), new Supplier() {

        @Override
        public void set(Object o) {
          accessible.setObject(o);
        }

        @Override
        public Object get() {
          return accessible.getObject();
        }
      });
    }
  };

  private static final SupplierInterface<Map<String, Object>> MAP_PARAM = new SupplierInterface<Map<String, Object>>() {
    @Override
    public void addToWrapper(SupplierContainer wrapper, Map<String, Object> target) {
      for (Map.Entry<String, Object> entry : target.entrySet()) {
        String key = entry.getKey();
        wrapper.put(key, new Supplier() {

          @Override
          public void set(Object o) {
            target.put(key, o);
          }

          @Override
          public Object get() {
            return target.get(key);
          }
        });
      }
    }
  };

  public SupplierContainer wrapper(Object obj) {
    if (obj instanceof SupplierContainer) {
      return (SupplierContainer) obj;
    }
    return DEFAULT.wrapper(obj);
  }

  public SupplierInterface factory(Object obj) {
    if (Map.class.isAssignableFrom(obj.getClass())) {
      return MAP_PARAM;
    }

    if (RootParam.class.isAssignableFrom(obj.getClass())) {
      return NAMED_PARAM;
    }

    String accessorClassName = getProviderClassName(obj);
    try {
      return (SupplierInterface) Class.forName(accessorClassName).newInstance();
    } catch (Exception ignore) {
    }
    return DEFAULT;
  }

  private static String getProviderClassName(Object obj) {
    return obj.getClass().getName() + "$Provider";
  }

  private static class SelfSupplier implements Supplier<Object> {

    private Object mValue;

    public SelfSupplier(Object value) {
      mValue = value;
    }

    @Override
    public Object get() {
      return mValue;
    }

    @Override
    public void set(Object o) {
      mValue = o;
    }
  }

}
